package com.jbm.core.common;

import com.google.protobuf.ByteString;
import com.google.protobuf.GeneratedMessage;
import com.jbm.core.iface.IAcross;
import com.jbm.core.pb.PBIAcross;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 * Created by root on 16-5-6.
 */
public class TransClass
{
	protected String m_pbpackage;
	protected String m_inpackage;
	protected HashMap<String,String> m_p2p;

	public TransClass ()
	{
	}

	public TransClass (String pbpackage, String inpackage )
	{
		m_pbpackage = pbpackage;
		m_inpackage = inpackage;
	}

	protected static String CamelCase (String name )
	{
		char nm[] = name.toCharArray();

		for ( int i = 0; i < nm.length; i ++ )
		{
			if ( nm[i] >= 'a' && nm[i] <= 'z' && ( i == 0 || nm[i-1] == '_') )
				nm[i] += ( 'A' - 'a' );
		}

		return String.valueOf(nm).replaceAll("_", "");
	}

	protected boolean P2I (Field field, Object pb, Object iface )
	{
		// 权限修饰符
		int mo = field.getModifiers();
		String priv = Modifier.toString(mo);
		// 属性类型
		Class<?> type = field.getType();

		String name = field.getName();

		int isclass = -1;
		String inpk = m_inpackage;

		for (int i = 0; i < AutoCall.g_autocall.getM_iface_classes().length; i ++ )
		{
			isclass = type.getName().indexOf(AutoCall.g_autocall.getM_iface_classes()[i]
					+ ".iface");

			if ( isclass != -1 )
			{
				inpk = AutoCall.g_autocall.getM_iface_classes()[i]
						+ ".iface";
				break;
			}
		}

		if ( type.isArray() && type.getComponentType() != byte.class )
		{
			String getlist = "get"+CamelCase(name)+"List";
			String getcount = "get"+CamelCase(name)+"Count";
			Object value = null;
			List<?> listpb = null;

			try
			{
				Method getlistm = pb.getClass().getMethod(getlist);
				Method getcountm = pb.getClass().getMethod(getcount);
				listpb = (List<?>)getlistm.invoke(pb);
				int count = Integer.parseInt(getcountm.invoke(pb).toString());

				value= Array.newInstance(type.getComponentType(), count);

				Iterator it = listpb.iterator();
				int i = 0;
				while ( it.hasNext())
				{
					Object li_value = it.next();
					String tinpk = m_inpackage;
					m_inpackage = inpk;
					if ( isclass != -1 )
						li_value = ProtocolBufferToI ( li_value );
					m_inpackage = tinpk;
					Array.set(value,i,li_value);
					i++;
				}
				field.setAccessible(true);
				field.set(iface, value);
			}catch ( Exception e)
			{
//				e.printStackTrace();
			}
		}else
		{
			String get = "get"+CamelCase(name);
			String has = "has"+CamelCase(name);
			Object value = null;

			try
			{
				Method getm = pb.getClass().getMethod(get);
				Method hasm = pb.getClass().getMethod(has);
				if ( (Boolean)hasm.invoke(pb) )
				{
					value = getm.invoke(pb);
					if (isclass != -1)
						value = ProtocolBufferToI(value);
					else if ( type.isArray() && type.getComponentType() == byte.class )
					{
						ByteString bs = (ByteString)value;
						value = bs.toByteArray();
					}
					field.setAccessible(true);
					field.set(iface, value);
				}
			}catch ( Exception e)
			{
//				e.printStackTrace();
			}
		}

		return true;
	}

	protected boolean I2P (Field field, Object pb, Object iface )
	{
		// 权限修饰符
		int mo = field.getModifiers();
		String priv = Modifier.toString(mo);
		// 属性类型
		Class<?> type = field.getType();

		String name = field.getName();

		int isclass = -1;
		String pbpk = m_pbpackage;

		for (int i = 0; i < AutoCall.g_autocall.getM_iface_classes().length; i ++ )
		{
			isclass = type.getName().indexOf(AutoCall.g_autocall.getM_iface_classes()[i]
					+ ".iface");

			if ( isclass != -1 )
			{
				pbpk = AutoCall.g_autocall.getM_iface_classes()[i]
						+ ".pb";
				break;
			}
		}

		if ( type.isArray() && type.getComponentType() != byte.class )
		{
			String add = "add" + CamelCase(name);
			Object value = null;

			try
			{
				field.setAccessible(true);
				value = field.get(iface);
				String svn = value.getClass().getComponentType().getSimpleName();
				Method addm = null;

				if ( isclass != -1 )
					addm = pb.getClass().getMethod(add, Class.forName(pbpk+".PB"+svn+"$"+svn));
				else
					addm = pb.getClass().getMethod(add,type.getComponentType());

				int count = Array.getLength(value);

				for ( int i = 0; i < count; i ++ )
				{
					Object li_value = Array.get(value,i);

					String tpbpk = m_pbpackage;
					m_pbpackage = pbpk;
					if ( isclass != -1 )
						li_value = ItoProtocolBuffer(li_value);
					m_pbpackage = tpbpk;

					addm.invoke(pb,li_value);
				}
			}catch (Exception e)
			{
				e.printStackTrace();
			}
		}else
		{
			String set = "set" + CamelCase(name);
			Object value = null;

			try
			{
				field.setAccessible(true);
				value = field.get(iface);
				Method setm = null;
				String svn = value.getClass().getSimpleName();

				if ( isclass != -1 )
				{
					setm = pb.getClass().getMethod(set, Class.forName(m_pbpackage+".PB" + svn + "$" + svn));
					value = ItoProtocolBuffer(value);
				}else if ( type.isArray() && type.getComponentType() == byte.class )
				{
					setm = pb.getClass().getMethod(set,ByteString.class);
				}else
					setm = pb.getClass().getMethod(set,type);

				if ( type.isArray() && type.getComponentType() == byte.class )
					value = ByteString.copyFrom((byte[])value);

				setm.invoke(pb,value);
			}catch (Exception e)
			{
//				e.printStackTrace();
			}
		}
		return true;
	}

	public Object ProtocolBufferToI (Object pb)
	{
		String iname = m_inpackage+"."+pb.getClass().getSimpleName();
		Class<?> demo = null;
		Object iface = null;

		try
		{
			demo = Class.forName(iname);
			iface = demo.newInstance();
		}catch (Exception e)
		{
//			e.printStackTrace();
		}

		if ( iface == null )
			return null;

		Field[] field = demo.getDeclaredFields();
/*		for (int i = 0; i < field.length; i++)
		{
			P2I( field[i], pb, iface);
		}*/
		// 取得实现的接口或者父类的属性
		Field[] field1 = demo.getFields();
		for (int j = 0; j < field1.length; j++)
		{
			P2I( field1[j], pb, iface);
		}

		return iface;
	}

	public Object ItoProtocolBuffer (Object iface )
	{
		Object pbb = null;

		Class<?> ifaceclass = iface.getClass();

		do
		{
			String pbname = m_pbpackage + ".PB" + ifaceclass.getSimpleName() + "$" + ifaceclass.getSimpleName();

			try
			{
				Method nb = Class.forName(pbname).getMethod("newBuilder");
				pbb = nb.invoke(null);
			} catch (Exception e)
			{
//			e.printStackTrace();
			}

			if ( pbb == null )
				ifaceclass = ifaceclass.getSuperclass();

		}while ( pbb == null && ifaceclass != null && !ifaceclass.getSimpleName().equals("IAcross"));

		if (pbb == null)
			return null;

		Class<?> demo = iface.getClass();

		Field[] field = demo.getDeclaredFields();
/*		for (int i = 0; i < field.length; i++)
		{
			I2P( field[i], pbb, iface);
		}*/
		// 取得实现的接口或者父类的属性
		Field[] field1 = demo.getFields();
		for (int j = 0; j < field1.length; j++)
		{
			I2P( field1[j], pbb, iface);
		}

		Object pb = null;

		try
		{
			Method build = pbb.getClass().getMethod("build");
			pb = build.invoke(pbb);
		}catch (Exception e)
		{
//			e.printStackTrace();
		}

		return pb;
	}

	public PBIAcross.IAcross I2_0toPB2_0(String errorheader, IAcross i2_0)
	{
		return I2_0toPB2_0Builder(errorheader, i2_0).build();
	}

	public PBIAcross.IAcross.Builder I2_0toPB2_0Builder(String errorheader, IAcross i2_0)
	{
		PBIAcross.IAcross.Builder builder = PBIAcross.IAcross.newBuilder();


		if ( i2_0.m_code != 0 )
			builder.setCode(i2_0.m_code);
		if ( i2_0.m_info != null )
			builder.setInfo(i2_0.m_info);
//		if ( i2_0.m_ca_key != null )
//			builder.setCaKey(i2_0.m_ca_key);
		if ( i2_0.m_query != null )
			builder.setQuery(i2_0.m_query);
		if ( i2_0.m_fromid != 0 )
			builder.setFromid(i2_0.m_fromid);
		if ( i2_0.m_toid != 0 )
			builder.setToid(i2_0.m_toid);
		if ( i2_0.m_fromtag != null )
			builder.setFromtag(i2_0.m_fromtag);
		if ( i2_0.m_totag != null )
			builder.setTotag(i2_0.m_totag);
		if ( i2_0.m_randr != 0 )
			builder.setRandr(i2_0.m_randr);
		if ( i2_0.m_qindex >= 0 )
			builder.setQindex(i2_0.m_qindex);

		if ( !i2_0.getClass().getSimpleName().equals("IAcross") )
		{
			builder.setClass_(i2_0.getClass().getSimpleName());

			GeneratedMessage pb = null;

			for (int i = 0; i < AutoCall.g_autocall.getM_iface_classes().length; i ++ )
			{
				if (i2_0.getClass().getName().indexOf(AutoCall.g_autocall.getM_iface_classes()[i]) != -1)
					pb = (GeneratedMessage) new TransClass(AutoCall.g_autocall.getM_iface_classes()[i] +
							".pb", AutoCall.g_autocall.getM_iface_classes()[i]
							+ ".iface").ItoProtocolBuffer(i2_0);

				if ( pb != null )
					break;
			}

			if ( pb != null )
			{
				builder.setContent(pb.toByteString());
			}else
			{
				builder.setCode(500);
				builder.setInfo(errorheader+i2_0.getClass().getName()+" I2P error");
			}
		}

		return builder;
	}

	public IAcross PB2_0toI2_0(String errorheader, PBIAcross.IAcross pb2_0)
	{
		int code = 0;
		String info = null;
		IAcross i2_0 = null;

		if (pb2_0.hasContent())
		{
			String pbname = null;
			String pkname = null;
			Class<?> pbcls = null;
			Method parsefrom = null;

			for ( int i = 0; i < AutoCall.g_autocall.getM_iface_classes().length; i ++ )
			{
				pbname = AutoCall.g_autocall.getM_iface_classes()[i] + ".pb.PB" + pb2_0.getClass_() + "$" + pb2_0.getClass_();
				pkname = AutoCall.g_autocall.getM_iface_classes()[i];
				try
				{
					pbcls = Class.forName(pbname);
				} catch (Exception e)
				{
				}

				if (pbcls != null)
					break;
			}

			if ( pbcls != null )
			{
				try
				{
					parsefrom = pbcls.getMethod("parseFrom", ByteString.class);
				}catch (Exception e)
				{
					code = 405;
					info = pbname+".parseFrom(byte[]) not found";
				}
			}else
			{
				code = 404;
				info = "PB" + pb2_0.getClass_() + " not found";
			}

			if ( parsefrom != null )
			{
				GeneratedMessage pbcontent = null;
				try
				{
					pbcontent = (GeneratedMessage) parsefrom.invoke(null, pb2_0.getContent());
				}catch (Exception e)
				{
					code = 500;
					info = pbname+".parseFrom(ByteString) invoke error";
				}

				if ( pbcontent != null )
				{
					i2_0 = (IAcross)new TransClass(pkname + ".pb", pkname + ".iface").ProtocolBufferToI(pbcontent);

					if (i2_0 == null)
					{
						code = 500;
						info = pbcontent.getClass().getName()+" P2I error";
					}
				}
			}
		}

		if ( i2_0 == null )
			i2_0 = new IAcross();

		if ( code != 0 )
			i2_0.m_code = code;
		else if (pb2_0.hasCode())
			i2_0.m_code = pb2_0.getCode();

		if ( info != null )
			i2_0.m_info = errorheader+info;
		else if (pb2_0.hasInfo())
			i2_0.m_info = pb2_0.getInfo();

//		if (pb2_0.hasCaKey())
//			i2_0.m_ca_key = pb2_0.getCaKey();
		if (pb2_0.hasQuery())
			i2_0.m_query = pb2_0.getQuery();
		if (pb2_0.hasFromid())
			i2_0.m_fromid = pb2_0.getFromid();
		if (pb2_0.hasToid())
			i2_0.m_toid = pb2_0.getToid();
		if (pb2_0.hasFromtag())
			i2_0.m_fromtag = pb2_0.getFromtag();
		if (pb2_0.hasTotag())
			i2_0.m_totag = pb2_0.getTotag();
		if (pb2_0.hasRandr())
			i2_0.m_randr = pb2_0.getRandr();
		if (pb2_0.hasQindex())
			i2_0.m_qindex = pb2_0.getQindex();

		return i2_0;
	}

	protected boolean P2P (Field field, Object pbb, Object ipb )
	{
		// 权限修饰符
		int mo = field.getModifiers();
		String priv = Modifier.toString(mo);
		// 属性类型
		Class<?> type = field.getType();

		String name = field.getName();

		Class<?> supertype = type;

		if ( type.isArray() )
			supertype = type.getComponentType();

		do
		{
			supertype = supertype.getSuperclass();
		}while ( supertype != null && !supertype.getSimpleName().equals("IAcross"));

		int isclass = supertype == null ? -1 : 0;

		if ( type.isArray() && type.getComponentType() != byte.class )
		{
			String add = "add" + CamelCase(name);

			String getlist = "get"+CamelCase(name)+"List";
			String getcount = "get"+CamelCase(name)+"Count";
			Object value = null;
			List<?> listpb = null;

			try
			{
				String svn = type.getComponentType().getSimpleName();
				Method addm = null;
				Field[] fields = null;

				if ( isclass != -1 )
				{
					addm = pbb.getClass().getMethod(add, Class.forName(m_pbpackage + ".PB" + svn + "$" + svn));
					fields = type.getComponentType().getFields();
				}else
					addm = pbb.getClass().getMethod(add,type.getComponentType());

				Method getlistm = ipb.getClass().getMethod(getlist);
				Method getcountm = ipb.getClass().getMethod(getcount);
				listpb = (List<?>)getlistm.invoke(ipb);
				int count = Integer.parseInt(getcountm.invoke(ipb).toString());

				Iterator it = listpb.iterator();

				while ( it.hasNext())
				{
					Object li_value = it.next();
					if ( isclass != -1 )
						li_value = PBtoPB (fields, li_value );
					addm.invoke(pbb,li_value);
				}
			}catch ( Exception e)
			{
				e.printStackTrace();
			}
		}else
		{
			String set = "set"+CamelCase(name);
			Method setm = null;
			String svn = type.getSimpleName();

			String get = "get"+CamelCase(name);
			String has = "has"+CamelCase(name);
			Object value = null;

			try
			{
				Method getm = ipb.getClass().getMethod(get);
				Method hasm = ipb.getClass().getMethod(has);
				if ( (Boolean)hasm.invoke(ipb) )
				{
					value = getm.invoke(ipb);

					if ( isclass != -1 )
					{
						setm = pbb.getClass().getMethod(set, Class.forName(m_pbpackage+".PB" + svn + "$" + svn));
						value = PBtoPB(type.getFields(), value);
					}else if ( type.isArray() && type.getComponentType() == byte.class )
					{
						setm = pbb.getClass().getMethod(set,ByteString.class);
					}else
						setm = pbb.getClass().getMethod(set,type);

					setm.invoke(pbb,value);
				}
			}catch ( Exception e)
			{
//				e.printStackTrace();
			}
		}
		return true;
	}

	protected Object PBtoPBBuilder(Field[] field, Object pb)
	{
		Object pbb = null;

		String pbname = m_p2p.get(pb.getClass().getSimpleName());
		if ( pbname == null )
			pbname = pb.getClass().getSimpleName();

		pbname = m_pbpackage + ".PB" +
				pbname
				+ "$" +
				pbname;

		try
		{
			Method nb = Class.forName(pbname).getMethod("newBuilder");
			pbb = nb.invoke(null);
		} catch (Exception e)
		{
//			e.printStackTrace();
		}

		if (pbb == null)
			return null;

		for (int j = 0; j < field.length; j++)
		{
			P2P( field[j], pbb, pb);
		}

		return pbb;
	}

	protected Object PBtoPB (Field[] field, Object pb)
	{
		Object pbb = PBtoPBBuilder(field,pb);

		if ( pbb == null )
			return null;

		Object rpb = null;

		try
		{
			Method build = pbb.getClass().getMethod("build");
			rpb = build.invoke(pbb);
		}catch (Exception e)
		{
//			e.printStackTrace();
		}

		return rpb;
	}

	public PBIAcross.IAcross I1_0toPB2_0(Object iface)
	{
		GeneratedMessage pb1_0 = (GeneratedMessage)
				new TransClass("com.jbm.jbmsupplier.pb","com.jbm.jbmsupplier.util")
				.ItoProtocolBuffer(iface);
		return PB1_0toPB2_0(pb1_0);
	}

	public PBIAcross.IAcross PB1_0toPB2_0(Object pb1_0)
	{
		m_p2p = OHCodeFactory.t10to20;

		String pb2_0clsname = m_p2p.get(pb1_0.getClass().getSimpleName());
		if ( pb2_0clsname == null )
			pb2_0clsname = pb1_0.getClass().getSimpleName();

		String pbname = null;
		Method nb = null;
		Class<?> pbcls = null;
		Method parsefrom = null;

		for ( int i = 0; i < AutoCall.g_autocall.getM_iface_classes().length; i ++ )
		{
			pbname = AutoCall.g_autocall.getM_iface_classes()[i] + ".pb.PB" + pb2_0clsname + "$" + pb2_0clsname;
			m_pbpackage = AutoCall.g_autocall.getM_iface_classes()[i] + ".pb";
			m_inpackage = AutoCall.g_autocall.getM_iface_classes()[i] + ".iface";

			try
			{
				nb = Class.forName(pbname).getMethod("newBuilder");
			} catch (Exception e)
			{
//			e.printStackTrace();
			}

			if ( nb != null )
				break;
		}

		if (nb == null)
			return null;

		try
		{
			Class<?> demo = Class.forName(m_inpackage + "." + pb2_0clsname);

			Field[] field = demo.getDeclaredFields();
			// 取得实现的接口或者父类的属性
			Field[] field1 = demo.getFields();

			GeneratedMessage pb = (GeneratedMessage) PBtoPB(field1, pb1_0);

			PBIAcross.IAcross.Builder builder = PBIAcross.IAcross.newBuilder();

			builder.setRandr(RandR.RANDR_TYPE_REQUEST);

			builder.setClass_(pb2_0clsname);
			builder.setMethod((String) pb1_0.getClass().getMethod("getMethod").invoke(pb1_0));

			if (pb != null)
				builder.setContent(pb.toByteString());
			else
			{
				builder.setCode(500);
				builder.setInfo(pb1_0.getClass().getName() + " PBtoPB error");
			}

			return builder.build();
		}catch (Exception e)
		{
			return null;
		}
	}

	public Object PB2_0toI1_0(PBIAcross.IAcross pb2_0)
	{
		GeneratedMessage pb1_0 = (GeneratedMessage)PB2_0toPB1_0(pb2_0);
		return new TransClass("com.jbm.jbmsupplier.pb","com.jbm.jbmsupplier.util")
						.ProtocolBufferToI(pb1_0);
	}

	public Object PB2_0toPB1_0(PBIAcross.IAcross pb2_0)
	{
		m_p2p = OHCodeFactory.t20to10;

		String pb1_0clsname = m_p2p.get(pb2_0.getClass_());
		if ( pb1_0clsname == null )
			pb1_0clsname = pb2_0.getClass_();

		GeneratedMessage pb = null;
		Class<?> pbcls = null;
		Method parsefrom = null;

		m_pbpackage = "com.jbm.jbmsupplier.pb";
		m_inpackage = "com.jbm.jbmsupplier.util";

		Class<?> demo = null;

		for ( int i = 0; i < AutoCall.g_autocall.getM_iface_classes().length; i ++ )
		{
			String ifacename = AutoCall.g_autocall.getM_iface_classes()[i] + ".iface." + pb2_0.getClass_();
			String pbname = AutoCall.g_autocall.getM_iface_classes()[i] + ".pb.PB" + pb2_0.getClass_() + "$" + pb2_0.getClass_();

			try
			{
				if ( demo == null )
					demo = Class.forName(ifacename);

				if ( pbcls == null )
					pbcls = Class.forName(pbname);
			} catch (Exception e)
			{
//			e.printStackTrace();
			}

			if ( demo != null && pbcls != null )
				break;
		}

		if (demo == null||pbcls == null)
			return null;

		try
		{
			parsefrom = pbcls.getMethod("parseFrom", ByteString.class);
			if ( parsefrom == null )
				return null;

			pb = (GeneratedMessage) parsefrom.invoke(null, pb2_0.getContent());
			if ( pb == null )
				return null;


			Field[] field = demo.getDeclaredFields();
			// 取得实现的接口或者父类的属性
			Field[] field1 = demo.getFields();

			Object pbb = PBtoPBBuilder(field1, pb);

			Method method = null;

			boolean back = pb2_0.getCode()==200?true:false;
			String ei = pb2_0.getInfo();

			try
			{

				pbb.getClass().getMethod("setBack",boolean.class).invoke(pbb,back);
			}catch (Exception e)
			{
			}
			try
			{

				pbb.getClass().getMethod("setErrorinfo", String.class).invoke(pbb,ei);
			}catch (Exception e)
			{
			}

			Object rpb = null;

			try
			{
				Method build = pbb.getClass().getMethod("build");
				rpb = build.invoke(pbb);
			}catch (Exception e)
			{
//			e.printStackTrace();
			}

			return rpb;
		}catch (Exception e)
		{
			return null;
		}
	}
}
